//
// Created by hay boy on 2022/6/17.
//

#include "ExtendedChain.h"



template<class T>
ExtendedChain<T>::ExtendedChain(int initialCapacity) :Chain<T>(initialCapacity){
    lastNode = nullptr;
}

template<class T>
ExtendedChain<T>::ExtendedChain(const ExtendedChain<T> &theList) {
    Chain<T>::listSize = theList.listSize;
    if(Chain<T>::listSize==0){
        Chain<T>::firstNode=nullptr;
        lastNode = nullptr;
        return;
    }
    ChainNode<T>* sourceNode = theList.firstNode;
    Chain<T>::firstNode = new ChainNode<T>(sourceNode->element);
    sourceNode = sourceNode->next;
    ChainNode<T>* targetNode = Chain<T>::firstNode;
    while(sourceNode!=nullptr){
        targetNode->next = new ChainNode<T>(sourceNode->element);
        targetNode = targetNode->next;
        sourceNode = sourceNode->next;
    }
    lastNode = targetNode;
    targetNode->next = nullptr;
}


template<class T>
void ExtendedChain<T>::clear() {
    while(Chain<T>::firstNode!=nullptr){
        ChainNode<T>* nextNode = Chain<T>::firstNode->next;
        delete Chain<T>::firstNode;
        Chain<T>::firstNode = nextNode;
    }
    lastNode = nullptr;
    Chain<T>::listSize = 0;
}

template<class T>
void ExtendedChain<T>::push_back(const T &theElement) {
    ChainNode<T>* newNode = new ChainNode<T>(theElement,nullptr);
    if(Chain<T>::firstNode==nullptr){
        Chain<T>::firstNode = lastNode = newNode;
    }else{
        lastNode->next = newNode;
        lastNode = newNode;
    }
    Chain<T>::listSize++;
}

template<class T>
void ExtendedChain<T>::erase(int theIndex) {
    Chain<T>::checkIndex(theIndex);
    ChainNode<T>* deleteNode;
    if(theIndex==0){
        deleteNode = Chain<T>::firstNode;
        Chain<T>::firstNode = Chain<T>::firstNode->next;
        if(Chain<T>::listSize==1){
            lastNode = nullptr;
        }
    }else{
        ChainNode<T>* p = Chain<T>::firstNode;
        for(int i = 0;i<theIndex-1;i++){
            p = p->next;
        }
        deleteNode = p->next;
        p->next = p->next->next;
        if(theIndex==Chain<T>::listSize-1){
            lastNode = p;
        }
    }
    Chain<T>::listSize--;
    delete deleteNode;
}

template<class T>
void ExtendedChain<T>::insert(int theIndex, const T &theElement) {
    if(theIndex<0||theIndex>Chain<T>::listSize){
        ostringstream s;
        s<<"index = "<<theIndex<<" size = "<<Chain<T>::listSize;
        throw illegalIndex(s.str());
    }
    if(theIndex==0){
        Chain<T>::firstNode = new ChainNode<T>(theElement,Chain<T>::firstNode);
        if(Chain<T>::listSize==0){
            lastNode = Chain<T>::firstNode;
        }
    }else{
        ChainNode<T>* p = Chain<T>::firstNode;
        for(int i = 0;i<theIndex-1;i++){
            p = p->next;
        }
        p->next = new ChainNode<T>(theElement,p->next);
        if(theIndex==Chain<T>::listSize){
            lastNode = p->next;
        }
    }
    Chain<T>::listSize++;
}

template<class Y>
ostream &operator<<(ostream &out, const ExtendedChain<Y> &x) {
    x.output(cout);
    return out;
}
